#include <iostream>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include "Metux.hpp"
using namespace MetuxModule;


//传自定义对象

int ticket = 1000;

class ThreadData
{
public:
    ThreadData(std::string name, Metux *lock)
    :_lock(lock),
    _name(name)
    {}

    ~ThreadData()
    {}
    Metux* _lock;
    std::string _name;
};

void* routine(void* argc)
{

    //char* id = static_cast<char*>(argc);
    ThreadData *td = static_cast<ThreadData*> (argc);
    while(true)
    {
        // 加锁：尽量加锁的范围粒度要比较细，尽可能的不要包含太多的非临界区代码
        //注意锁放到位置，这也很重要S
        //td->_lock->Lock();
        LockGuard Lock(td->_lock->Lock());  // 加锁完成, RAII风格的互斥锁的实现
        //lock.Lock();
        if(ticket > 0)
        {
            //临界区
            usleep(1000);
            ticket--;
            std::cout << td->_name << " sell the tickets; ticket numble: " << ticket << std::endl;
           // lock.UnLock();
           //td->_lock->UnLock();
        }
        else
        {
            //td->_lock->UnLock();
            //lock.UnLock();
            break;
        } 

    }
    return nullptr;
}



//模拟抢票环境，体现线程的互斥的现象
// int ticket = 1000;

//pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;;
//Metux lock;
// void* routine(void* argc)
// {

//     char* id = static_cast<char*>(argc);

//     while(true)
//     {
//         // 加锁：尽量加锁的范围粒度要比较细，尽可能的不要包含太多的非临界区代码
//         //注意锁放到位置，这也很重要S
//         LockGuard Lock(lock);
//         //lock.Lock();
//         if(ticket > 0)
//         {
//             //临界区
//             usleep(1000);
//             ticket--;
//             std::cout << id << " sell the tickets; ticket numble: " << ticket << std::endl;
//            // lock.UnLock();
//         }
//         else
//         {
//             //lock.UnLock();
//             break;
//         } 

//     }
//     return nullptr;
// }

int main()
{
    
    pthread_t t1, t2, t3, t4;
    
    Metux lock;
    ThreadData *td1 = new ThreadData("thread-1", &lock);
    pthread_create(&t1, nullptr, routine, (void*)td1);
    
    ThreadData *td2 = new ThreadData("thread-2", &lock);
    pthread_create(&t2, nullptr, routine, (void*)td2);
    
    ThreadData *td3 = new ThreadData("thread-3", &lock);
    pthread_create(&t3, nullptr, routine, (void*)td3);
    
    
    ThreadData *td4 = new ThreadData("thread-4", &lock);
    pthread_create(&t4, nullptr, routine, (void*)td4);

    pthread_join(t1, nullptr);
    pthread_join(t2, nullptr);
    pthread_join(t3, nullptr);
    pthread_join(t4, nullptr);

    return 0;
}